package cn.klaw.encrypt;

import cn.hutool.core.net.url.UrlQuery;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.klaw.constant.GlobalConst;
import cn.klaw.constant.MsgCode;
import cn.klaw.exception.EncryptFailException;
import cn.klaw.wrapper.MyRequestWrapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import cn.klaw.annotation.EncryptApi;
import cn.klaw.util.DesUtil;
import cn.klaw.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;

import java.net.URLDecoder;
import java.util.*;

/**
 * 接口传输加密
 * 支持请求类型:
 * application/json
 * application/x-www-form-urlencoded
 */
@Slf4j
public class EncryptRestInterceptor implements AsyncHandlerInterceptor {

    private static final String ENCRYPT_KEY = "encryptData";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            if (handler instanceof HandlerMethod && request instanceof MyRequestWrapper) {
                HandlerMethod method = (HandlerMethod) handler;
                EncryptApi methodAnnotation = method.getMethodAnnotation(EncryptApi.class);
                if (methodAnnotation != null && methodAnnotation.encryptRequest()) {
                    MyRequestWrapper myRequest = (MyRequestWrapper) request;
                    // 需要对数据进行加密解密
                    // application/json
                    // application/x-www-form-urlencoded
                    String contentType = request.getContentType();
                    if (contentType != null) {
                        String requestBody = null;
                        boolean canEncrypt = false;
                        if ((StringUtils.substringMatch(contentType, 0,
                                MediaType.APPLICATION_FORM_URLENCODED_VALUE)) || "get".equalsIgnoreCase(request.getMethod())) {
                            // 1.application/x-www-form-urlencoded 支持参数在body或者在param
                            canEncrypt = true;
                            requestBody = convertFormToString(request);
                            if ("{}".equals(requestBody)) {
                                requestBody = URLDecoder.decode(myRequest.getRequestBody());
                                Map<CharSequence, CharSequence> uriToListToMap = new UrlQuery().parse(requestBody, GlobalConst.DEFAULT_CHARSET).getQueryMap();
                                requestBody = JSONObject.toJSONString(uriToListToMap);
                            }

                        } else if (StringUtils.substringMatch(contentType, 0, MediaType.APPLICATION_JSON_VALUE)) {
                            // application/json 支持加密参数在body
                            canEncrypt = true;
                            requestBody = myRequest.getRequestBody();
                        }
                        if (canEncrypt) {
                            if (requestBody != null && !"{}".equals(requestBody)) {
                                JSONObject jsonBody = JSON.parseObject(requestBody);
                                JSON result = decodeApi(jsonBody);
                                if (result != null) {
                                    myRequest.setRequestBody(result.toJSONString());
                                    if (result instanceof JSONObject) {
                                        myRequest.addAllParameters((Map<String, Object>) result);
                                    }
                                    return true;
                                }
                            }
                        }
                    }
                    throw encryptFailException();
                }
            }
        } catch (EncryptFailException eex) {
            throw eex;
        } catch (Exception e) {
            log.error("解密失败, 异常地址：{}", request.getServletPath(), e);
            throw encryptFailException();
        }
        return true;
    }

    /**
     * Pamams参数转JSON字符串
     *
     * @param request
     * @return
     */
    private String convertFormToString(HttpServletRequest request) {
        Map<String, String> result = new HashMap<>(8);
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            result.put(name, request.getParameter(name));
        }
        try {
            return JSON.toJSONString(result);
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }


    /**
     * 请求内容解密
     *
     * @param body
     * @return
     */
    public JSON decodeApi(JSON body) {
        try {
            JSONObject jsonObject = (JSONObject) body;
            String content = jsonObject.getOrDefault(ENCRYPT_KEY, "").toString();
            if (!StringUtil.isEmpty(content)) {
                content = decryptData(content);
                return (JSON) JSON.parse(content);
            }
        } catch (Exception e) {
            log.error("解密失败, 文本: {}", body, e);
        }
        return null;
    }

    /**
     * 文本解密
     *
     * @param data
     * @return
     */
    protected String decryptData(String data) {
        if (StringUtil.isEmpty(data)) {
            return data;
        }
        if (Objects.equals(data.charAt(0), '"') && Objects.equals(data.charAt(data.length() - 1), '"')) {
            data = data.substring(1, data.length() - 1);
        }
        return DesUtil.aesOrDecode(data, false, true);
    }

    private EncryptFailException encryptFailException() {
        throw new EncryptFailException(MsgCode.FA051.get());
    }
}
